package visitor;

import syntaxtree.*;
import symbol.*;

public class TypeDepthFirstVisitor implements TypeVisitor {

	private Table symbolTable = new Table();

	// MainClass m;
	// ClassDeclList cl;
	public Type visit(Program n) {
		n.m.accept(this);
		for ( int i = 0; i < n.cl.size(); i++ ) {
			n.cl.elementAt(i).accept(this);
		}
		return null;
	}

	// Identifier i1,i2;
	// Statement s;
	public Type visit(MainClass n) {
		symbolTable.beginScope();
		n.i1.accept(this);
		n.i2.accept(this);
		n.s.accept(this);
		symbolTable.endScope();
		return null;
	}

	// Identifier i;
	// VarDeclList vl;
	// MethodDeclList ml;
	public Type visit(ClassDeclSimple n) {

		symbolTable.beginScope();
		n.i.accept(this);
		for ( int i = 0; i < n.vl.size(); i++ ) {
			n.vl.elementAt(i).accept(this);
		}
		for ( int i = 0; i < n.ml.size(); i++ ) {
			n.ml.elementAt(i).accept(this);
		}
		symbolTable.endScope();
		return null;
	}

	// Identifier i;
	// Identifier j;
	// VarDeclList vl;
	// MethodDeclList ml;
	public Type visit(ClassDeclExtends n) {
		symbolTable.beginScope();
		n.i.accept(this);
		n.j.accept(this);
		for ( int i = 0; i < n.vl.size(); i++ ) {
			n.vl.elementAt(i).accept(this);
		}
		for ( int i = 0; i < n.ml.size(); i++ ) {
			n.ml.elementAt(i).accept(this);
		}
		symbolTable.endScope();
		return null;
	}

	// Type t;
	// Identifier i;
	public Type visit(VarDecl n){

		try {
			symbolTable.put(Symbol.symbol(n.i.toString()), (Object)n.t);
		} catch (Exception e) {
			System.out.println("Problema encontrado: " + e.toString());
		}
		n.t.accept(this);
		n.i.accept(this);
		return null;
	}

	// Type t;
	// Identifier i;
	// FormalList fl;
	// VarDeclList vl;
	// StatementList sl;
	// Exp e;
	public Type visit(MethodDecl n) {
		symbolTable.beginScope();
		n.t.accept(this);
		n.i.accept(this);
		for ( int i = 0; i < n.fl.size(); i++ ) {
			n.fl.elementAt(i).accept(this);
		}
		for ( int i = 0; i < n.vl.size(); i++ ) {
			n.vl.elementAt(i).accept(this);
		}
		for ( int i = 0; i < n.sl.size(); i++ ) {
			n.sl.elementAt(i).accept(this);
		}
		n.e.accept(this);
		symbolTable.endScope();
		return null;
	}

	// Type t;
	// Identifier i;
	public Type visit(Formal n) {
		try {
			symbolTable.put(Symbol.symbol(n.i.toString()), (Object) n.t);
		} catch (Exception e) {
			System.out.println("Problema encontrado: " + e.toString());
		}
		n.t.accept(this);
		n.i.accept(this);
		return null;
	}

	public Type visit(IntArrayType n) {
		return n;
	}

	public Type visit(BooleanType n) {
		return n;
	}

	public Type visit(IntegerType n) {
		return n;
	}

	// String s;
	public Type visit(IdentifierType n) {
		return n;
	}

	// StatementList sl;
	public Type visit(Block n) {
		symbolTable.beginScope();
		for ( int i = 0; i < n.sl.size(); i++ ) {
			n.sl.elementAt(i).accept(this);
		}
		symbolTable.endScope();
		return null;
	}

	// Exp e;
	// Statement s1,s2;
	public Type visit(If n) {
		n.e.accept(this);
		
		symbolTable.beginScope();
		n.s1.accept(this);
		symbolTable.endScope();
		
		symbolTable.beginScope();
		n.s2.accept(this);
		symbolTable.endScope();
		return null;
	}

	// Exp e;
	// Statement s;
	public Type visit(While n) {
		symbolTable.beginScope();
		n.e.accept(this);
		n.s.accept(this);
		symbolTable.endScope();
		return null;
	}

	// Exp e;
	public Type visit(Print n) {
		n.e.accept(this);
		return null;
	}

	// Identifier i;
	// Exp e;
	public Type visit(Assign n) {
		n.i.accept(this);
		n.e.accept(this);
		return null;
	}

	// Identifier i;
	// Exp e1,e2;
	public Type visit(ArrayAssign n) {
		/*Type tipo;
		try {
			tipo = (Type)symbolTable.get(Symbol.symbol(n.i.toString()));
		} catch (Exception e) {
			System.out.println("Problema :" + e.toString());
		}*/
		n.i.accept(this);
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	// Exp e1,e2;
	public Type visit(And n) {
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	// Exp e1,e2;
	public Type visit(LessThan n) {
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	// Exp e1,e2;
	public Type visit(Plus n) {
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	// Exp e1,e2;
	public Type visit(Minus n) {
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	// Exp e1,e2;
	public Type visit(Times n) {
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	// Exp e1,e2;
	public Type visit(ArrayLookup n) {
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	// Exp e;
	public Type visit(ArrayLength n) {
		n.e.accept(this);
		return null;
	}

	// Exp e;
	// Identifier i;
	// ExpList el;
	public Type visit(Call n) {
		n.e.accept(this);
		n.i.accept(this);
		for ( int i = 0; i < n.el.size(); i++ ) {
			n.el.elementAt(i).accept(this);
		}
		return null;
	}

	// int i;
	public Type visit(IntegerLiteral n) {
		return new IntegerType();
	}

	public Type visit(True n) {
		return new BooleanType();
	}

	public Type visit(False n) {
		return new BooleanType();
	}

	// String s;
	public Type visit(IdentifierExp n) {
		Type tipo = null;
		try {
			tipo = (Type)symbolTable.get(Symbol.symbol(n.s));
		} catch (Exception e) {
			System.out.println("Problema :" + e.toString());
		}
		return tipo;
	}

	public Type visit(This n) {
		return null;
	}

	// Exp e;
	public Type visit(NewArray n) {
		n.e.accept(this);
		return null;
	}

	// Identifier i;
	public Type visit(NewObject n) {
		return null;
	}

	// Exp e;
	public Type visit(Not n) {
		n.e.accept(this);
		return null;
	}

	// String s;
	public Type visit(Identifier n) {
		return null;
	}

	@Override
	public Type visit(GreaterThan n) {
		// TODO Auto-generated method stub
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	@Override
	public Type visit(LessEqualThan n) {
		// TODO Auto-generated method stub
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}

	@Override
	public Type visit(GreaterEqualThan n) {
		// TODO Auto-generated method stub
		n.e1.accept(this);
		n.e2.accept(this);
		return null;
	}
}
